package com.msh.artascope.devcloud.service.service.impl;


import com.msh.artascope.devcloud.client.po.DefalutResourcePo;
import com.msh.artascope.devcloud.client.po.DomainConfigPo;
import com.msh.artascope.devcloud.client.po.EnvPo;
import com.msh.artascope.devcloud.client.po.GitlabConfigPo;
import com.msh.artascope.devcloud.client.po.HealthTestPo;
import com.msh.artascope.devcloud.client.po.JenkinsConfigPo;
import com.msh.artascope.devcloud.client.po.KubernetesConfigPo;
import com.msh.artascope.devcloud.client.po.LogConfigPo;
import com.msh.artascope.devcloud.client.po.ModuleBuildPo;
import com.msh.artascope.devcloud.client.po.ModuleNetworkPo;
import com.msh.artascope.devcloud.client.po.ModulePo;
import com.msh.artascope.devcloud.client.po.ModuleResourcePo;
import com.msh.artascope.devcloud.client.po.ModuleReverseProxyPo;
import com.msh.artascope.devcloud.client.po.ModuleRunPo;
import com.msh.artascope.devcloud.client.po.ProductPo;
import com.msh.artascope.devcloud.client.po.ProjectPo;
import com.msh.artascope.devcloud.client.po.RegisterConfigPo;
import com.msh.artascope.devcloud.client.qo.DefalutResourceQo;
import com.msh.artascope.devcloud.client.qo.DomainConfigQo;
import com.msh.artascope.devcloud.client.qo.EnvQo;
import com.msh.artascope.devcloud.client.qo.GitlabConfigQo;
import com.msh.artascope.devcloud.client.qo.HealthTestQo;
import com.msh.artascope.devcloud.client.qo.LogConfigQo;
import com.msh.artascope.devcloud.client.qo.ModuleBuildQo;
import com.msh.artascope.devcloud.client.qo.ModuleNetworkQo;
import com.msh.artascope.devcloud.client.qo.ModuleQo;
import com.msh.artascope.devcloud.client.qo.ModuleResourceQo;
import com.msh.artascope.devcloud.client.qo.ModuleReverseProxyQo;
import com.msh.artascope.devcloud.client.qo.ModuleRunQo;
import com.msh.artascope.devcloud.client.qo.ProductQo;
import com.msh.artascope.devcloud.client.qo.ProjectQo;
import com.msh.artascope.devcloud.client.qo.RegisterConfigQo;
import com.msh.artascope.devcloud.service.dao.EnvDao;
import com.msh.artascope.devcloud.service.define.DevCloudDef;
import com.msh.artascope.devcloud.service.model.page.ModuleHealthTestVo;
import com.msh.artascope.devcloud.service.model.query.EnvQueryVo;
import com.msh.artascope.devcloud.service.model.vo.EnvVo;
import com.msh.artascope.devcloud.service.service.DefalutResourceService;
import com.msh.artascope.devcloud.service.service.DomainConfigService;
import com.msh.artascope.devcloud.service.service.EnvService;
import com.msh.artascope.devcloud.service.service.GitlabConfigService;
import com.msh.artascope.devcloud.service.service.HealthTestService;
import com.msh.artascope.devcloud.service.service.JenkinsConfigService;
import com.msh.artascope.devcloud.service.service.KubernetesConfigService;
import com.msh.artascope.devcloud.service.service.LogConfigService;
import com.msh.artascope.devcloud.service.service.ModuleBuildService;
import com.msh.artascope.devcloud.service.service.ModuleNetworkService;
import com.msh.artascope.devcloud.service.service.ModuleResourceService;
import com.msh.artascope.devcloud.service.service.ModuleReverseProxyService;
import com.msh.artascope.devcloud.service.service.ModuleRunService;
import com.msh.artascope.devcloud.service.service.ModuleService;
import com.msh.artascope.devcloud.service.service.ProductService;
import com.msh.artascope.devcloud.service.service.ProjectService;
import com.msh.artascope.devcloud.service.service.RegisterConfigService;
import com.msh.artascope.devcloud.service.wrapper.JenkinsWrapper;
import com.msh.artascope.devcloud.service.wrapper.K8sWrapper;
import com.msh.artascope.devcloud.service.wrapper.K8sWrapper.K8sInfo;
import com.msh.controller.starter.fuzzy.search.model.qo.FuzzySearchQo;
import com.msh.controller.starter.fuzzy.search.service.FuzzySearchService;
import com.msh.frame.client.base.SortBy;
import com.msh.frame.client.base.TenantBaseServiceImpl;
import com.msh.frame.client.common.Result;
import com.msh.frame.client.define.ColumnDef;
import com.msh.frame.client.exception.BizException;
import com.msh.frame.interfaces.IdGenerateable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

/**
 * @author shihu
 * @mail m-sh@qq.com
 */
@Service
@Slf4j
public class EnvServiceImpl extends TenantBaseServiceImpl<EnvPo,EnvQo> implements EnvService {

  @Resource
  private EnvDao envDao;

  @Resource
  private IdGenerateable idGenerateable;

  @Resource
  @Lazy
  private KubernetesConfigService kubernetesConfigService;

  @Resource
  @Lazy
  private GitlabConfigService gitlabConfigService;

  @Resource
  @Lazy
  private JenkinsConfigService jenkinsConfigService;

  @Resource
  @Lazy
  private RegisterConfigService registerConfigService;

  @Resource
  @Lazy
  private DefalutResourceService defalutResourceService;
  @Resource
  @Lazy
  private DomainConfigService domainConfigService;

  @Resource
  @Lazy
  private LogConfigService logConfigService;

  @Resource
  @Lazy
  private ModuleService moduleService;

  @Resource
  @Lazy
  private ProductService productService;

  @Resource
  @Lazy
  private ProjectService projectService;

  @Resource
  @Lazy
  private ModuleBuildService moduleBuildService;

  @Resource
  @Lazy
  private ModuleResourceService moduleResourceService;

  @Resource
  @Lazy
  private HealthTestService healthTestService;

  @Resource
  @Lazy
  private ModuleRunService moduleRunService;

  @Resource
  @Lazy
  private ModuleNetworkService moduleNetworkService;

  @Resource
  @Lazy
  private ModuleReverseProxyService moduleReverseProxyService;

  @Resource
  @Lazy
  private K8sWrapper k8sWrapper;

  @Resource
  @Lazy
  private JenkinsWrapper jenkinsWrapper;

  @Resource
  @Lazy
  private FuzzySearchService fuzzySearchService;


  @Override
  public long insert(EnvPo param) {
    param.setId(idGenerateable.getUniqueId());
    return super.insert(param);
  }

  @Override
  public int insertCollection(Collection<EnvPo> param) {
    param.forEach(p->p.setId(idGenerateable.getUniqueId()));
    return super.insertCollection(param);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void update(EnvPo param) {
    Long id = param.getId();
    Long tenantId = param.getTenantId();
    EnvPo envPo = this.get(id, tenantId);
    BizException.doThrowIfNull("环境不存在", envPo);
    if(!StringUtils.isEmpty(param.getEnv()) && !param.getEnv().equals(envPo.getEnv())){
      //修改环境名称
      List<ModulePo> list = moduleService.list(new ModuleQo().setEnvId(id).setTenantId(tenantId).setColumns(ColumnDef.ID, ColumnDef.NAME));
      Set<Long> moduleIdSet = list
              .stream().map(ModulePo::getId).collect(Collectors.toSet());
      fuzzySearchService.deleteByQo(new FuzzySearchQo().setPrimaryIdIn(moduleIdSet));
      for(ModulePo modulePo: list){
        fuzzySearchService.insertCollection(modulePo.getName(),
            DevCloudDef.FUZZY_SEARCH_TYPE_MODULE_NAME,
            modulePo.getId(), modulePo.getName() + "-" + param.getEnv(), param.getTenantId());
      }
    }
    super.update(param);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public int delete(Long id, Long tenantId) {
    EnvPo envPo = get(id, tenantId);
    BizException.doThrowIfNull("无法获取当前环境", envPo);
    if(!envPo.getTenantId().equals(tenantId)){
      return 0;
    }
    KubernetesConfigPo kubernetesConfigPo = kubernetesConfigService.getByEnvId(envPo.getId(), tenantId);
    gitlabConfigService.deleteByQo(new GitlabConfigQo().setEnvId(envPo.getId()).setTenantId(tenantId), tenantId);
    JenkinsConfigPo jenkinsConfigPo = jenkinsConfigService.getByEnvId(envPo.getId(), tenantId);
    registerConfigService.deleteByQo(new RegisterConfigQo().setEnvId(envPo.getId()).setTenantId(tenantId), tenantId);
    defalutResourceService.deleteByQo(new DefalutResourceQo().setEnvId(envPo.getId()).setTenantId(tenantId), tenantId);
    logConfigService.deleteByQo(new LogConfigQo().setEnvId(envPo.getId()).setTenantId(tenantId), tenantId);
    int delete = super.delete(id, tenantId);

    List<ProjectPo> projectPoList = projectService.list(new ProjectQo().setEnvId(envPo.getId()).setTenantId(tenantId).setColumns(ColumnDef.ID, ColumnDef.NAME));
    Set<Long> projectIdSet = projectPoList.stream().map(ProjectPo::getId).collect(Collectors.toSet());
    deleteProjectInfo(jenkinsConfigPo, envPo, projectPoList, tenantId);

    if(null != kubernetesConfigPo){
      kubernetesConfigService.delete(kubernetesConfigPo.getId(), tenantId);
      deleteNamespace(kubernetesConfigPo, envPo, projectIdSet);
    }

    return delete;
  }


// ----------前端vo处理-------------------------------------------------------

  private EnvVo toVo(EnvPo po){
    return po.convert(EnvVo.class);
  }

  private List<EnvVo> toVoList(List<EnvPo> list){
    if(CollectionUtils.isEmpty(list)){
      return Collections.emptyList();
    }

    return list.stream().map(this::toVo).collect(Collectors.toList());
  }

  @Override
  public EnvVo getVo(Long id, Long tenantId) {
    EnvPo po = this.get(id, tenantId);
    if(null == po){
      return null;
    }

    return toVo(po);
  }

  @Override
  public List<EnvVo> listVo(EnvQueryVo q){
    EnvQo qo = q.convert(EnvQo.class);
    List<EnvPo> poList = this.list(qo);

    return toVoList(poList);
  }

  @Override
  public Result<List<EnvVo>> pageVo(EnvQueryVo param) {
    EnvQo qo = param.convert(EnvQo.class);
    int count = this.count(qo);
    if (0 == count) {
      return Result.successReturn(Collections.<EnvVo>emptyList()).setCount(count);
    }
    List<EnvPo> poList = this.list(qo);
    List<EnvVo> voList = toVoList(poList);

    return Result.successReturn(voList).setCount(count);
  }

  @Override
  public EnvVo copyEnvConfig(Long id, String newEnv, String newNamespace, Long tenantId) {
    EnvPo envPo = get(id, tenantId);
    Long envId = envPo.getId();
    BizException.doThrowIfTrue("非法参数", !envPo.getTenantId().equals(tenantId));
    EnvPo newEnvPo = listOne(new EnvQo().setEnv(newEnv).setTenantId(tenantId));
    BizException.doThrowIfTrue(newEnv + "环境已存在", null != newEnvPo);
    GitlabConfigPo gitlabConfigPo = gitlabConfigService.getByEnvId(envId, tenantId);
    BizException.doThrowIfNull("缺少git配置参数", gitlabConfigPo);
    JenkinsConfigPo jenkinsConfigPo = jenkinsConfigService.getByEnvId(envId, tenantId);
    BizException.doThrowIfNull("缺少jenkins配置参数", jenkinsConfigPo);
    KubernetesConfigPo kubernetesConfigPo = kubernetesConfigService.getByEnvId(envId, tenantId);
    BizException.doThrowIfNull("缺少k8s配置参数", kubernetesConfigPo);
    RegisterConfigPo registerConfigPo = registerConfigService.getByEnvId(envId, tenantId);
    BizException.doThrowIfNull("缺少镜像仓库配置参数", registerConfigPo);
    DefalutResourcePo defalutResourcePo = defalutResourceService.getByEnvId(envId, tenantId);
    BizException.doThrowIfNull("缺少默认资源配置参数", defalutResourcePo);

    LogConfigPo logConfigPo = logConfigService.getByEnvId(envId, tenantId);

    newEnvPo = new EnvPo();
    newEnvPo.setEnv(newEnv);
    newEnvPo.setNamespace(newNamespace);
    newEnvPo.setTenantId(tenantId);
    long newEnvId = this.insert(newEnvPo);

    gitlabConfigPo.setId(null);
    gitlabConfigPo.setEnvId(newEnvId);
    gitlabConfigPo.setUpdateVersion(1);
    gitlabConfigService.insert(gitlabConfigPo);

    jenkinsConfigPo.setId(null);
    jenkinsConfigPo.setEnvId(newEnvId);
    jenkinsConfigPo.setUpdateVersion(1);
    jenkinsConfigService.insert(jenkinsConfigPo);

    kubernetesConfigPo.setId(null);
    kubernetesConfigPo.setEnvId(newEnvId);
    kubernetesConfigPo.setUpdateVersion(1);
    kubernetesConfigService.insert(kubernetesConfigPo);

    registerConfigPo.setId(null);
    registerConfigPo.setEnvId(newEnvId);
    registerConfigPo.setUpdateVersion(1);
    registerConfigService.insert(registerConfigPo);

    defalutResourcePo.setId(null);
    defalutResourcePo.setEnvId(newEnvId);
    defalutResourcePo.setUpdateVersion(1);
    defalutResourceService.insert(defalutResourcePo);

    if(null != logConfigPo){
      logConfigPo.setId(null);
      logConfigPo.setEnvId(newEnvId);
      logConfigPo.setUpdateVersion(1);
      logConfigService.insert(logConfigPo);
    }

    return toVo(newEnvPo);
  }

  @Override
  public void copyProjectConfig(Long sourceEnvId, Long targetEnvId, Collection<Long> projectIds, Long tenantId) {
    if(CollectionUtils.isEmpty(projectIds)){
      return;
    }

    EnvPo source = get(sourceEnvId, tenantId);
    BizException.doThrowIfNull("无法获取源环境信息", source);
    EnvPo target = get(targetEnvId, tenantId);
    BizException.doThrowIfNull("无法获取目标环境信息", target);

    // 开始复制项目，包含jenkins
    List<ProjectPo> projectPoList = projectService.list(
        new ProjectQo().setIdIn(projectIds).setEnvId(sourceEnvId).setTenantId(tenantId));
    if (CollectionUtils.isEmpty(projectPoList)) {
      return;
    }

    JenkinsConfigPo jenkinsConfigPo = jenkinsConfigService.getByEnvId(targetEnvId, tenantId);
    BizException.doThrowIfNull("无法获取jenkins配置信息", target);
    DefalutResourcePo defalutResourcePo = defalutResourceService.getByEnvId(targetEnvId, tenantId);
    BizException.doThrowIfNull("无法获取默认资源配置信息", defalutResourcePo);

    // 需要复制的制品列表
    List<ModulePo> sourceModulePoList = moduleService.list(
        new ModuleQo().setProjectIdIn(projectIds).setTenantId(tenantId));

    // 新旧环境的域名id映射
    Map<Long, Long> domainConfigIdMap = new HashMap<>();
    Map<Long, List<ModuleReverseProxyPo>> moduleReverseProxyListMap;
    if (!CollectionUtils.isEmpty(sourceModulePoList)) {
      Set<Long> moduleIdSet = sourceModulePoList.stream().map(ModulePo::getId)
          .collect(Collectors.toSet());
      List<ModuleReverseProxyPo> reverseProxyPoList = moduleReverseProxyService.list(
          new ModuleReverseProxyQo().setModuleIdIn(moduleIdSet));
      moduleReverseProxyListMap = reverseProxyPoList.stream()
          .collect(Collectors.groupingBy(ModuleReverseProxyPo::getModuleId));
      if (null != reverseProxyPoList) {
        // 新环境需要使用的域名id集合
        Set<Long> domainConfidIdSet = reverseProxyPoList.stream()
            .map(ModuleReverseProxyPo::getDomainConfigId)
            .collect(Collectors.toSet());

        List<DomainConfigPo> domainConfigPoList = domainConfigService.list(
            new DomainConfigQo().setEnvIdIn(Arrays.asList(sourceEnvId, targetEnvId))
                .setTenantId(tenantId));

        if (!CollectionUtils.isEmpty(domainConfigPoList)) {
          // 需要的域名列表
          List<DomainConfigPo> needDomainList = domainConfigPoList.stream()
              .filter(d -> domainConfidIdSet.contains(d.getId())).collect(Collectors.toList());
          BizException.doThrowIfTrue("域名配置信息不一致",
              needDomainList.size() != domainConfidIdSet.size());

          // 目标环境域名列表
          List<DomainConfigPo> targetDomainList = domainConfigPoList.stream()
              .filter(d -> d.getEnvId().equals(targetEnvId)).collect(Collectors.toList());

          needDomainList.forEach(d -> {
            // 新域名
            String newDomain = d.getDomain().replace(source.getNamespace(), target.getNamespace());
            DomainConfigPo domainConfigPo = targetDomainList.stream()
                .filter(t -> t.getDomain().equals(newDomain)).findAny().orElse(null);
            BizException.doThrowIfNull("未配置域名: " + newDomain, domainConfigPo);
            domainConfigIdMap.put(d.getId(), domainConfigPo.getId());
          });
        }
      }
    } else {
      moduleReverseProxyListMap = Collections.emptyMap();
    }

    // 目标现有的项目
    List<ProjectPo> targetProjectPoList = projectService.list(
        new ProjectQo().setEnvId(targetEnvId).setTenantId(tenantId));
    Set<String> projectNameSet = targetProjectPoList
        .stream()
        .map(ProjectPo::getName).collect(Collectors.toSet());
    List<ModulePo> targetModulePoList = moduleService.list(
        new ModuleQo().setEnvId(targetEnvId).setTenantId(tenantId));
    Set<String> ModuleNameSet = targetModulePoList
        .stream()
        .map(ModulePo::getName).collect(Collectors.toSet());

    Map<Long, List<ModulePo>> projectModuleMap = sourceModulePoList.stream()
        .collect(Collectors.groupingBy(ModulePo::getProjectId));

    for (ProjectPo projectPo : projectPoList) {
      // 复制环境已存在项目， 跳过
      if (projectNameSet.contains(projectPo.getName())) {
        continue;
      }
      List<ModulePo> modulePoList = projectModuleMap.get(projectPo.getId());
      Set<Long> moduleIdSet = modulePoList.stream().map(ModulePo::getId)
          .collect(Collectors.toSet());
      ProjectPo copy = projectService.copy(projectPo, jenkinsConfigPo, target);
      List<ModuleResourcePo> moduleResourceInsert = new LinkedList<>();
      List<ModuleNetworkPo> moduleNetworkInsert = new LinkedList<>();
      List<ModuleReverseProxyPo> moduleReverseProxyInsert = new LinkedList<>();
      List<HealthTestPo> healthTestInsert = new LinkedList<>();
      List<ModuleBuildPo> moduleBuildInsert = new LinkedList<>();
      List<ModuleRunPo> moduleRunInsert = new LinkedList<>();
      if(!CollectionUtils.isEmpty(modulePoList)){
        Map<Long, ModuleNetworkPo> moduleNetworkMap = moduleNetworkService.list(new ModuleNetworkQo().setModuleIdIn(moduleIdSet).setTenantId(tenantId))
                .stream().collect(Collectors.toMap(ModuleNetworkPo::getModuleId, m -> m));
        Map<Long, List<HealthTestPo>> healthTestListMap = healthTestService.list(new HealthTestQo().setModuleIdIn(moduleIdSet).setTenantId(tenantId))
                .stream().collect(Collectors.groupingBy(HealthTestPo::getModuleId));
        for (ModulePo modulePo: modulePoList){
          // 复制环境已存在模块， 跳过
          if(ModuleNameSet.contains(modulePo.getName())){
            continue;
          }
          Long oldId = modulePo.getId();
          // 创建模块
          modulePo.setId(null);
          modulePo.setEnvId(targetEnvId);
          modulePo.setCreateTime(null);
          modulePo.setUpdateTime(null);
          modulePo.setUpdateVersion(1);
          modulePo.setProjectId(copy.getId());
          moduleService.insert(modulePo, target);
          // 创建资源配置
          ModuleResourcePo moduleResourcePo = new ModuleResourcePo();
          moduleResourcePo.setModuleId(modulePo.getId());
          moduleResourcePo.setProjectId(modulePo.getProjectId());
          moduleResourcePo.setJavaArgs(defalutResourcePo.getJavaArgs());
          moduleResourcePo.setDiskSize(defalutResourcePo.getDiskSize());
          moduleResourcePo.setMaxMem(defalutResourcePo.getMaxMem());
          moduleResourcePo.setMinMem(defalutResourcePo.getMinMem());
          moduleResourcePo.setReplicasNum(defalutResourcePo.getReplicasNum());
          moduleResourcePo.setTenantId(tenantId);
          moduleResourceInsert.add(moduleResourcePo);
          // 创建网络配置
          ModuleNetworkPo moduleNetworkPo = moduleNetworkMap.get(oldId);
          if (null != moduleNetworkPo) {
            moduleNetworkPo.setModuleId(modulePo.getId());
            moduleNetworkPo.setCreateTime(null);
            moduleNetworkPo.setUpdateTime(null);
            moduleNetworkPo.setUpdateVersion(1);
            moduleNetworkInsert.add(moduleNetworkPo);
            // 创建反向代理
            List<ModuleReverseProxyPo> moduleReverseProxyPoList = moduleReverseProxyListMap.get(
                oldId);
            if (!CollectionUtils.isEmpty(moduleReverseProxyPoList)) {
              moduleReverseProxyPoList.stream().forEach(item -> {
                item.setId(null);
                item.setProjectId(null);
                item.setModuleId(modulePo.getId());
                item.setCreateTime(null);
                item.setUpdateTime(null);
                item.setUpdateVersion(1);
                item.setDomainConfigId(domainConfigIdMap.get(item.getDomainConfigId()));
                item.setEnvId(targetEnvId);
                moduleReverseProxyInsert.add(item);
              });
            }
          }

          // 健康检测
          List<HealthTestPo> healthTestList = healthTestListMap.get(oldId);
          if(!CollectionUtils.isEmpty(healthTestList)){
            healthTestList.forEach(health->{
              health.setModuleId(modulePo.getId());
              health.setId(null);
              health.setUpdateVersion(1);
              healthTestInsert.add(health);
            });
          }
          ModuleRunPo moduleRunPo = moduleRunService.listOne(new ModuleRunQo().setModuleId(oldId).setSortBy(SortBy.desc("id")).setPageSize(1));
          if(null != moduleRunPo && !"stop".equals(moduleRunPo.getOperation())){
            Long moduleBuildId = moduleRunPo.getModuleBuildId();
            ModuleBuildPo moduleBuildPo = moduleBuildService.get(moduleBuildId, tenantId);
            if(null != moduleBuildPo){
              Long[] uniqueIds = idGenerateable.getUniqueIds(2);
              moduleBuildPo.setId(uniqueIds[0]);
              moduleBuildPo.setModuleId(modulePo.getId());
              moduleBuildPo.setProjectId(modulePo.getProjectId());
              moduleBuildPo.setBuildNum(0);
              moduleBuildInsert.add(moduleBuildPo);
              moduleRunPo.setId(uniqueIds[1]);
              moduleRunPo.setModuleId(modulePo.getId());
              moduleRunPo.setModuleBuildId(moduleBuildPo.getId());
              moduleRunPo.setProjectId(modulePo.getProjectId());
              moduleRunInsert.add(moduleRunPo);
            }
          }
        }
      }
      if (!CollectionUtils.isEmpty(moduleResourceInsert)) {
        moduleResourceService.insertCollection(moduleResourceInsert);
      }
      if (!CollectionUtils.isEmpty(moduleNetworkInsert)) {
        moduleNetworkService.insertCollection(moduleNetworkInsert);
      }
      if (!CollectionUtils.isEmpty(moduleReverseProxyInsert)) {
        moduleReverseProxyService.insertCollection(moduleReverseProxyInsert);
      }
      if (!CollectionUtils.isEmpty(healthTestInsert)) {
        healthTestService.insertCollection(healthTestInsert);
      }
      if (!CollectionUtils.isEmpty(moduleBuildInsert)) {
        moduleBuildService.insertCollection(moduleBuildInsert);
      }
      if (!CollectionUtils.isEmpty(moduleRunInsert)) {
        moduleRunService.insertCollection(moduleRunInsert);
      }
    }
  }

  @Override
  public void deleteNamespace(Long id, Long tenantId){
    EnvPo envPo = this.get(id, tenantId);
    BizException.doThrowIfNull("无法获取当前环境", envPo);
    KubernetesConfigPo kubernetesConfigPo = kubernetesConfigService.getByEnvId(envPo.getId(), tenantId);
    BizException.doThrowIfNull("缺少k8s配置信息", kubernetesConfigPo);
    JenkinsConfigPo jenkinsConfigPo = jenkinsConfigService.getByEnvId(envPo.getId(), tenantId);
    BizException.doThrowIfNull("缺少jenkins配置信息", jenkinsConfigPo);
    List<ProjectPo> projectPoList = projectService.list(new ProjectQo().setEnvId(envPo.getId()).setTenantId(tenantId).setColumns(ColumnDef.ID));
    Set<Long> projectIdSet = projectPoList.stream().map(ProjectPo::getId).collect(Collectors.toSet());
    deleteNamespace(kubernetesConfigPo, envPo, projectIdSet);
    removeJenkinsJob(jenkinsConfigPo, projectPoList, envPo);
  }

  private void deleteNamespace(KubernetesConfigPo kubernetesConfigPo, EnvPo envPo, Set<Long> projectIdSet){
    K8sInfo k8sInfo = new K8sInfo(kubernetesConfigPo.getAddress(), kubernetesConfigPo.getToken(), envPo.getNamespace());
    k8sWrapper.deleteNamespace(k8sInfo);
    if(!CollectionUtils.isEmpty(projectIdSet)){
      moduleBuildService.clearBuildNum(new ModuleBuildQo().setProjectIdIn(projectIdSet));
    }
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void deleteProjectInfo(Long id, Long tenantId) {
    EnvPo envPo = get(id, tenantId);
    BizException.doThrowIfNull("无法获取当前环境", envPo);
    if(!envPo.getTenantId().equals(tenantId)){
      return;
    }
    JenkinsConfigPo jenkinsConfigPo = jenkinsConfigService.getByEnvId(id, tenantId);
    List<ProjectPo> projectPoList = projectService.list(new ProjectQo().setEnvId(envPo.getId()).setTenantId(tenantId).setColumns(ColumnDef.ID, ColumnDef.NAME));
    deleteProjectInfo(jenkinsConfigPo, envPo, projectPoList, tenantId);
  }

  private void deleteProjectInfo(JenkinsConfigPo jenkinsConfigPo, EnvPo envPo, List<ProjectPo> projectPoList, Long tenantId) {
    if(!CollectionUtils.isEmpty(projectPoList)){
      Set<Long> projectIdSet = projectPoList.stream().map(ProjectPo::getId).collect(Collectors.toSet());
      projectService.deleteByIds(projectIdSet, tenantId);
      Set<Long> moduleIdSet = moduleService.list(new ModuleQo().setEnvId(envPo.getId()).setTenantId(tenantId).setColumns(ColumnDef.ID))
              .stream().map(ModulePo::getId).collect(Collectors.toSet());
      if(!CollectionUtils.isEmpty(moduleIdSet)){
        moduleService.deleteByIds(moduleIdSet, tenantId);
        moduleReverseProxyService.deleteByQo(new ModuleReverseProxyQo().setModuleIdIn(moduleIdSet),
            tenantId);
        moduleBuildService.deleteByQo(new ModuleBuildQo().setModuleIdIn(moduleIdSet), tenantId);
        moduleNetworkService.deleteByQo(new ModuleNetworkQo().setModuleIdIn(moduleIdSet), tenantId);
        moduleResourceService.deleteByQo(new ModuleResourceQo().setModuleIdIn(moduleIdSet), tenantId);
        moduleRunService.deleteByQo(new ModuleRunQo().setModuleIdIn(moduleIdSet), tenantId);
        healthTestService.deleteByQo(new HealthTestQo().setModuleIdIn(moduleIdSet), tenantId);
        fuzzySearchService.deleteByQo(
            new FuzzySearchQo().setTypeId(DevCloudDef.FUZZY_SEARCH_TYPE_MODULE_NAME)
                .setPrimaryIdIn(moduleIdSet));
      }
      if(null != jenkinsConfigPo){
        removeJenkinsJob(jenkinsConfigPo, projectPoList, envPo);
      }
    }
  }

  private void removeJenkinsJob(JenkinsConfigPo jenkinsConfigPo, List<ProjectPo> projectPoList, EnvPo envPo){
    if(null != jenkinsConfigPo){
      for(ProjectPo projectPo: projectPoList){
        try {
          jenkinsWrapper.removeJob(jenkinsConfigPo, envPo.getNamespace(), projectPo.getName());
        }catch (BizException e){
        }
      }
    }
  }

  @Override
  public void initNamespace(Long id, Long tenantId){
    EnvPo envPo = this.get(id, tenantId);
    BizException.doThrowIfNull("无法获取当前环境", envPo);
    Long envId = envPo.getId();
    KubernetesConfigPo kubernetesConfigPo = kubernetesConfigService.getByEnvId(envId, tenantId);
    BizException.doThrowIfNull("缺少k8s配置信息", kubernetesConfigPo);
    BizException.doThrowIfNull("缺少默认资源配置信息", defalutResourceService.getByEnvId(envId, tenantId));
    BizException.doThrowIfNull("缺少git服务配置信息", gitlabConfigService.getByEnvId(envId, tenantId));
    JenkinsConfigPo jenkinsConfigPo = jenkinsConfigService.getByEnvId(envId, tenantId);
    BizException.doThrowIfNull("缺少jenkins配置信息", jenkinsConfigPo);
    RegisterConfigPo registerConfigPo = registerConfigService.getByEnvId(envId, tenantId);
    BizException.doThrowIfNull("缺少镜像仓库配置信息", registerConfigPo);

    startBuildJenkinsProject(jenkinsConfigPo, envPo, tenantId);
    K8sInfo k8sInfo = new K8sInfo(kubernetesConfigPo.getAddress(), kubernetesConfigPo.getToken(), envPo.getNamespace());
    BizException.doThrowIfTrue("命名空间已存在", k8sWrapper.hasNamespace(k8sInfo));
    startBuildNamespace(k8sInfo, registerConfigPo, envId, kubernetesConfigPo.getFilebeatOutAddr(), tenantId);
  }

  private void startBuildJenkinsProject(JenkinsConfigPo configPo, EnvPo envPo, Long tenantId){
    String namespace = envPo.getNamespace();
    List<ProjectPo> list = projectService.list(new ProjectQo().setEnvId(envPo.getId()).setTenantId(tenantId));
    list.forEach(p->{
      if(!jenkinsWrapper.hasJob(configPo, namespace, p.getName())){
        jenkinsWrapper.createJob(configPo, namespace, p.getName());
      }
    });
  }

  private void startBuildNamespace(K8sInfo k8sInfo, RegisterConfigPo registerConfigPo, Long envId, String filebeatOutAddr, Long tenantId){
    k8sWrapper.createNamespace(k8sInfo);
    k8sWrapper.createConfigmap(k8sInfo, filebeatOutAddr);
    Map<Long, ProductPo> productMap = productService.map(new ProductQo().setTenantId(tenantId));
    if(CollectionUtils.isEmpty(productMap)){
      return;
    }
    Map<Long, ProjectPo> projectMap = projectService.map(new ProjectQo().setTenantId(tenantId).setEnvId(envId));
    if(CollectionUtils.isEmpty(projectMap)){
      return;
    }
    List<ModulePo> modulePoList = moduleService.list(new ModuleQo().setTenantId(tenantId).setEnvId(envId));
    if(CollectionUtils.isEmpty(modulePoList)){
      return;
    }
    for(ModulePo modulePo: modulePoList){
      Long moduleId = modulePo.getId();
      String name = modulePo.getName();
      try {
        log.info("服务 {} 创建任务开始.....", name);
        ProjectPo projectPo = projectMap.get(modulePo.getProjectId());
        if(null == projectPo){
          log.info("服务 {} 缺少项目信息, 跳过...", name);
          continue;
        }
        ProductPo productPo = productMap.get(projectPo.getProductId());
        if(null == productPo){
          log.info("服务 {} 缺少产品信息, 跳过...", name);
          continue;
        }

        ModuleRunPo moduleRunPo = moduleRunService.listOne(new ModuleRunQo().setModuleId(moduleId).setSortBy(SortBy.desc("id")).setPageSize(1));
        if(null == moduleRunPo){
          log.info("服务 {} 缺少运行信息, 跳过...", name);
          continue;
        }
        if("stop".equals(moduleRunPo.getOperation())){
          log.info("服务 {} 最后为停止操作, 跳过...", name);
          continue;
        }
        Long moduleBuildId = moduleRunPo.getModuleBuildId();
        ModuleBuildPo moduleBuildPo = moduleBuildService.get(moduleBuildId, tenantId);
        if(null == moduleBuildPo){
          log.info("服务 {} 缺少构建信息, 跳过...", name);
          continue;
        }

        ModuleResourcePo moduleResourcePo = moduleResourceService
            .listOne(new ModuleResourceQo().setModuleId(moduleBuildPo.getModuleId())
                .setTenantId(tenantId));
        if (null == moduleResourcePo) {
          log.info("服务 {} 缺少资源信息, 跳过...", name);
          continue;
        }
        ModuleHealthTestVo moduleHealthTestVo = healthTestService
            .moduleHealthTest(moduleBuildPo.getModuleId(), moduleBuildPo.getTenantId());
        k8sWrapper.createDeployment(k8sInfo, productPo, modulePo, moduleBuildPo, moduleResourcePo,
            registerConfigPo, moduleHealthTestVo,
            Collections.emptyMap());
        log.info("服务 {} deploy创建完成", name);
        ModuleNetworkPo moduleNetworkPo = moduleNetworkService.listOne(
            new ModuleNetworkQo().setModuleId(moduleId).setTenantId(tenantId));
        if (null == moduleNetworkPo) {
          log.info("服务 {} 没有网络信息", name);
          continue;
        }
        k8sWrapper.createService(k8sInfo, modulePo, moduleNetworkPo);
      } finally {
        log.info("服务 {} 创建任务结束.....", name);
      }
    }
    // TODO: 创建 域名
    // TODO: 创建 域名的istio-vs
  }
}
